home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / MISC / DTMFF110 / SETUPSUB.C < prev   
C/C++ Source or Header  |  1997-08-05  |  21KB  |  700 lines

  1. /*
  2.  *  Routines for setting up the parameters/buffers/display
  3.  *
  4.  *  Copyright (C) 1995    Philip VanBaren (C) 1996 Emil LAURENTIU
  5.  */
  6. #include <math.h>
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <conio.h>
  10. #include <string.h>
  11. #include <ctype.h>
  12.  
  13. #include "freq.h"
  14. #include "extern.h"
  15. #include "display.h"
  16.  
  17. int          fftlen = 1024;    /* Number of points for FFT */
  18. long          SampleRate = 20000L;    /* A/D sampling rate */
  19. int          logfreq = 0;    /* Flag set to 1 for log-based frequency
  20.                  * scale */
  21. float          ys = 0.1;        /* Flag set for max of y-axis */
  22. float          threshold_level = 0.05;    /* Treshold level used in DTMF &
  23.                      * CTCSS modes */
  24. int          dtmf_delay = 80;    /* 1/3 Length of generated DTMF tones in ms */
  25.  
  26. int          Soundcard = SC_DEF;    /* Soundcard number (as defined in
  27.                      * freq.h) */
  28. int          sb_irq = SB_IRQ;    /* IRQ used by the Soundblaster card */
  29. int          sb_dma = SB_DMA;    /* DMA channel used by the Soundblaster card */
  30. int          sb_addr = SB_ADDR;/* I/O address of the Soundblaster card */
  31. float          maxfreq;
  32. double          alpha;        /* Gaussian window parameter */
  33.  
  34. struct rgb    background = {0, 0, 20},
  35.           warn = {20, 0, 0},
  36.           graph = {30, 35, 60},
  37.           tick = {40, 40, 40},
  38.           label = {0, 63, 0},
  39.           border = {63, 0, 0},
  40.           text = {63, 63, 0},
  41.           darkhl = {20, 20, 20},
  42.           lighthl = {63, 63, 63};
  43.  
  44. /* Center frequencies for equalizer-mode display */
  45. double          center_freq[] = {4, 5, 6.3, 8, 10, 12.5, 16, 20, 25, 31.5, 40, 50,
  46.   63, 80, 100, 125, 160, 200, 250, 315, 400, 500, 630,
  47.   800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000,
  48. 6300, 8000, 10000, 12500, 16000, 20000, 25000};
  49.  
  50. #define EQUALIZER_BINS (sizeof(center_freq)/sizeof(center_freq[0]))
  51.  
  52. /* Soundcard function pointers */
  53. void          ( *init_soundcard ) ( void ) = NULL;
  54. void          ( *reset_soundcard ) ( void ) = NULL;
  55. void          ( *halt_soundcard ) ( void ) = NULL;
  56. void          ( *cleanup_soundcard ) ( void ) = NULL;
  57. void          ( *recordblock ) ( void far * ) = NULL;
  58. void          ( *set_mixer ) ( int, int ) = NULL;
  59. int          sample_size;    /* Bits per sample (8 or 16) */
  60. int          mixers;        /* Mixers available (1) or not (0) */
  61.  
  62. #include <alloc.h>
  63.  
  64. void far     *
  65. aligned_malloc( long len )
  66. {
  67.   void far     *ptr;
  68.   unsigned int far *orig_ptr;
  69.   unsigned    seg, orig_seg, orig_off;
  70.   long        lin_addr;
  71.  
  72.   /* Allocate double the required space */
  73.   ptr = farmalloc( len * 2 + 32 );
  74.   if ( ptr != NULL )
  75.   {
  76.     /* Compute a new pointer to the buffer such that the next "len" bytes */
  77.     /* do not cross a page boundary, and the offset is zero */
  78.     /* (as required by DMA transfers) */
  79.     orig_off = FP_OFF( ptr );
  80.     orig_seg = FP_SEG( ptr );
  81.     /* reserve 4 bytes for the original pointer */
  82.     lin_addr = ( orig_seg * 16L ) + orig_off + 4L;
  83.     if ( ( lin_addr & 0xF0000L ) != ( ( lin_addr + len - 1 ) & 0xF0000L ) )
  84.       lin_addr = ( lin_addr + len - 1 ) & 0xF0000L;
  85.     else
  86.       lin_addr = ( lin_addr + 15 ) & 0xFFFF0L;
  87.  
  88.     seg = ( unsigned int ) ( lin_addr / 16 );
  89.     orig_ptr = ( unsigned far * ) MK_FP( seg - 1, 0x000C );
  90.     orig_ptr[0] = orig_off;
  91.     orig_ptr[1] = orig_seg;
  92.     ptr = MK_FP( seg, 0 );
  93.     /*
  94.      * printf("Original: %04x:%04x, New: %04x:%04x, Linear: %05lx\n",
  95.      * orig_seg,orig_off,FP_SEG(ptr),FP_OFF(ptr),lin_addr);
  96.      */
  97.   }
  98.   return ptr;
  99. }
  100.  
  101. void
  102. aligned_free( void far * ptr )
  103. {
  104.   if ( ptr != NULL )
  105.   {
  106.     unsigned far *old_ptr = ( unsigned far * ) MK_FP( FP_SEG( ptr ) - 1, 0x000c );
  107.     /*
  108.      * printf("Freeing: %04x:%04x, Ptr: %04x:%04x\n",
  109.      * FP_SEG(old_ptr),FP_OFF(old_ptr),FP_SEG(ptr),FP_OFF(ptr));
  110.      */
  111.     farfree( MK_FP( old_ptr[1], old_ptr[0] ) );
  112.   }
  113. }
  114.  
  115. /*
  116.  *  Parse the ini file, if it exists
  117.  */
  118. void
  119. parse_ini_file( void )
  120. {
  121.   int        i;
  122.   FILE           *fp;
  123.   char        buffer[100];
  124.  
  125.   if ( ( fp = fopen( ini_file, "r" ) ) != NULL )
  126.   {
  127.     while ( !feof( fp ) )
  128.     {
  129.       fgets( buffer, sizeof( buffer ), fp );
  130.       for ( i = 0; ( buffer[i] != 0 ) && ( buffer[i] != ':' ); i++ )
  131.     buffer[i] = toupper( buffer[i] );
  132.  
  133.       if ( strncmp( buffer, "SOUNDCARD:", 10 ) == 0 )
  134.     Soundcard = parsecardname( buffer + 10 );
  135.       sscanf( buffer, "SAMPLE RATE:%ld", &SampleRate );
  136.       sscanf( buffer, "FFT LENGTH:%d", &fftlen );
  137.       sscanf( buffer, "LOG FREQ SCALE:%d", &logfreq );
  138.       sscanf( buffer, "MAX AMP:%f", &ys );
  139.       sscanf( buffer, "BASE FREQUENCY:%f", &freq_base );
  140.       sscanf( buffer, "FREQUENCY FACTOR:%f", &freq_scalefactor );
  141.       sscanf( buffer, "DTMF & CTCSS THRESHOLD LEVEL:%f", &threshold_level );
  142.       sscanf( buffer, "DTMF DELAY (100 - 1000 MS):%d", &dtmf_delay );
  143.       sscanf( buffer, "CTCSS ACTIVE:%lx,%lx", &ctcss_act1, &ctcss_act2 );
  144.       sscanf( buffer, "BACKGROUND COLOR:%d,%d,%d", &background.red, &background.green, &background.blue );
  145.       sscanf( buffer, "CLIPPING WARNING COLOR:%d,%d,%d", &warn.red, &warn.green, &warn.blue );
  146.       sscanf( buffer, "GRAPH COLOR:%d,%d,%d", &graph.red, &graph.green, &graph.blue );
  147.       sscanf( buffer, "TICK MARK COLOR:%d,%d,%d", &tick.red, &tick.green, &tick.blue );
  148.       sscanf( buffer, "AXIS LABEL COLOR:%d,%d,%d", &label.red, &label.green, &label.blue );
  149.       sscanf( buffer, "BORDER COLOR:%d,%d,%d", &border.red, &border.green, &border.blue );
  150.       sscanf( buffer, "TEXT COLOR:%d,%d,%d", &text.red, &text.green, &text.blue );
  151.       sscanf( buffer, "CURSOR UPPER COLOR:%d,%d,%d", &darkhl.red, &darkhl.green, &darkhl.blue );
  152.       sscanf( buffer, "CURSOR LOWER COLOR:%d,%d,%d", &lighthl.red, &lighthl.green, &lighthl.blue );
  153.     }
  154.     fclose( fp );
  155.     dtmf_delay /= 3;
  156.   }
  157. }
  158.  
  159. void
  160. setnormalpalette( void )
  161. {
  162.   draw_setpalette( 0, background.red, background.green, background.blue );
  163.   draw_setpalette( LABEL_COLOR, label.red, label.green, label.blue );
  164.   draw_setpalette( BORDER_COLOR, border.red, border.green, border.blue );
  165.   draw_setpalette( TEXT_COLOR, text.red, text.green, text.blue );
  166.   draw_setpalette( GRAPH_COLOR, graph.red, graph.green, graph.blue );
  167.   draw_setpalette( DARK_HIGHLIGHT, darkhl.red, darkhl.green, darkhl.blue );
  168.   draw_setpalette( LIGHT_HIGHLIGHT, lighthl.red, lighthl.green, lighthl.blue );
  169. }
  170.  
  171. void
  172. setbwpalette( void )
  173. {
  174.   draw_setpalette( 0, 0, 0, 0 );
  175.   draw_setpalette( LABEL_COLOR, 63, 63, 63 );
  176.   draw_setpalette( BORDER_COLOR, 63, 63, 63 );
  177.   draw_setpalette( TEXT_COLOR, 63, 63, 63 );
  178.   draw_setpalette( GRAPH_COLOR, 63, 63, 63 );
  179.   draw_setpalette( DARK_HIGHLIGHT, 20, 20, 20 );
  180.   draw_setpalette( LIGHT_HIGHLIGHT, 63, 63, 63 );
  181. }
  182.  
  183. /*
  184.  * Parse the command line
  185.  */
  186. void
  187. parse_command( int argc, char *argv[], char *environ[] )
  188. {
  189.   int        i = 0;
  190.  
  191.   while ( i < argc )
  192.   {
  193.     if ( argv[i][0] == '-' )
  194.     {
  195.       switch ( argv[i][1] )
  196.       {
  197.     case 'C':               /* Select the sound card */
  198.     case 'c':
  199.       Soundcard = parsecardname( argv[i] + 2 );
  200.       break;
  201.     case 'S':               /* Set the sampling rate (in Hz) */
  202.     case 's':
  203.       SampleRate = atol( &argv[i][2] );
  204.       break;
  205.     case 'F':               /* Set the FFT length */
  206.     case 'f':
  207.       fftlen = atoi( &argv[i][2] );
  208.       break;
  209.     case 'M':               /* Set the maximum value for linear display */
  210.     case 'm':
  211.       ys = atof( &argv[i][2] );
  212.       break;
  213.     case 'L':               /* Set logarithmic frequency scale */
  214.     case 'l':
  215.       logfreq = 1;
  216.       break;
  217.     case '?':               /* Display some help information */
  218.     case 'H':
  219.     case 'h':
  220.       puts( "-Cnumber selects the soundcard (0=SB, 1=SB16)." );
  221.       puts( "-Snumber sets the sampling rate." );
  222.       puts( "-Fnumber sets the length of the FFT." );
  223.       puts( "-Mnumber sets the scale maximum." );
  224.       puts( "-L sets a logarithmic scale for the frequency axis." );
  225.       puts( "-? or -H displays this message." );
  226.       exit( 0 );
  227.     default:
  228.       printf( "Ignoring unrecognized switch: %s\n", argv[i] );
  229.       puts( "Press <ENTER> to continue..." );
  230.       getch(  );
  231.       }
  232.     }
  233.     else
  234.       printf( "Ignoring unrecognized parameter: %s  (use -h for help)\n", argv[i] );
  235.     i++;
  236.   }
  237.  
  238.   /*
  239.    * Watch for bad choice of log scales
  240.    */
  241.   if ( ys > 2.0 )
  242.     ys = 2.0;
  243.   if ( ys < 0.01 )
  244.     ys = 0.01;
  245.  
  246.   if ( SampleRate > 88200L )
  247.     SampleRate = 88200L;
  248.   if ( SampleRate < 5000L )
  249.     SampleRate = 5000L;
  250.  
  251.   if ( fftlen < 8 )
  252.     fftlen = 8;
  253.   if ( fftlen > MAX_LEN )
  254.     fftlen = MAX_LEN;
  255.   /* Convert fftlen to a power of 2 */
  256.   for ( i = 0; fftlen > 1; fftlen >>= 1, i++ );
  257.   if ( i )
  258.     fftlen <<= i;
  259.  
  260.   /* Set up the soundcard function pointers */
  261. #ifdef SC_SB8
  262.   if ( Soundcard == SC_SB8 )
  263.     init_sb8( environ );
  264. #endif
  265. #ifdef SC_SB16
  266.   if ( Soundcard == SC_SB16 )
  267.     init_sb16( environ );
  268. #endif
  269.   if ( reset_soundcard == NULL )
  270.   {
  271.     puts( "Error: Invalid soundcard selection" );
  272.     puts( "Valid choices are:" );
  273. #ifdef SC_SB8
  274.     printf( "  %s (%d)\n", SC_SB8_NAME, SC_SB8 );
  275. #endif
  276. #ifdef SC_SB16
  277.     printf( "  %s (%d)\n", SC_SB16_NAME, SC_SB16 );
  278. #endif
  279.     exit( 1 );
  280.   }
  281. }
  282.  
  283. /* Parse a sound card number or label */
  284. int
  285. parsecardname( char *label )
  286. {
  287.   int        i = 0, j;
  288.   char        name[10];
  289.  
  290.   /* Skip over any leading space */
  291.   while ( label[i] == ' ' )
  292.     i++;
  293.  
  294.   /* Check for numerical values */
  295.   if ( label[i] <= '9' )
  296.     return ( label[i] - '0' );
  297.  
  298.   /* Convert the string to upper case */
  299.   for ( j = 0; label[i] && ( j < 9 ); i++, j++ )
  300.     name[j] = toupper( label[i] );
  301.   name[j] = 0;
  302.  
  303.   /* Check for valid string values */
  304. #ifdef SC_SB8
  305.   if ( strncmp( name, SC_SB8_NAME, strlen( SC_SB8_NAME ) ) == 0 )
  306.     return SC_SB8;
  307. #endif
  308. #ifdef SC_SB16
  309.   if ( strncmp( name, SC_SB16_NAME, strlen( SC_SB16_NAME ) ) == 0 )
  310.     return SC_SB16;
  311. #endif
  312.   return ( -1 );        /* If none match, return failure */
  313. }
  314.  
  315. /*
  316.  *  Allocate memory for and initialize the buffers
  317.  */
  318. void
  319. setup_buffers( int length )
  320. {
  321.   int        i, ll;
  322.   char far     *p;
  323.  
  324.   for ( i = 0; i < BUFFERS; i++ )
  325.   {
  326.     if ( ( buffer[i] = aligned_malloc( length * ( sample_size / 8 ) ) ) == NULL )
  327.     {
  328.       puts( "Unable to allocate enough memory for the buffers!" );
  329.       exit( 1 );
  330.     }
  331.     /* Pre-set the buffer to all zeros */
  332.     p = buffer[i];
  333.     for ( ll = 0; ll < length * ( sample_size / 8 ); ll++ )
  334.       *p++ = 0;
  335.     flag[i] = 0;
  336.   }
  337.  
  338.   if ( ( fftdata = ( short * ) malloc( length * sizeof( short ) ) ) == NULL )
  339.   {
  340.     puts( "Unable to allocate enough memory for the buffers!" );
  341.     exit( 1 );
  342.   }
  343.   if ( ( wind = ( short * ) malloc( length * sizeof( short ) ) ) == NULL )
  344.   {
  345.     puts( "Unable to allocate enough memory for the buffers!" );
  346.     exit( 1 );
  347.   }
  348.   if ( ( displayval = ( long * ) malloc( length / 2 * sizeof( long ) ) ) == NULL )
  349.   {
  350.     puts( "Unable to allocate enough memory for the buffers!" );
  351.     exit( 1 );
  352.   }
  353.   if ( ( ybase = ( long * ) malloc( length / 2 * sizeof( long ) ) ) == NULL )
  354.   {
  355.     puts( "Unable to allocate enough memory for the buffers!" );
  356.     exit( 1 );
  357.   }
  358.   /*
  359.    * Clear out the memory buffers
  360.    */
  361.   for ( i = 0; i < ( WINDOW_RIGHT - WINDOW_LEFT + 1 ); i++ )
  362.     lasty[i] = WINDOW_BOTTOM;
  363. }
  364.  
  365. void
  366. compute_window_function( void )
  367. {
  368.   int        i;
  369.   /*
  370.    * Calculate FFT Windowing function
  371.    */
  372.   for ( i = 0; i < fftlen; i++ )
  373.   {
  374.     double      val;
  375.  
  376.     val = 0.54 - 0.46 * cos( 2 * M_PI * i / fftlen );    /* Hamming */
  377.     wind[i] = floor( val * 32767 + 0.5 );
  378.   }
  379. }
  380.  
  381.  
  382. /*
  383.  *  Do some range checking on the base and scale factors
  384.  */
  385. void
  386. xrange_check( void )
  387. {
  388.   if ( freq_scalefactor < 1.0 )
  389.     freq_scalefactor = 1.0;
  390.   if ( freq_scalefactor > 16.0 )
  391.     freq_scalefactor = 16.0;
  392.  
  393.   if ( logfreq )
  394.   {
  395.     double      max_base = SampleRate / 2 / exp( log( fftlen / 2 ) / freq_scalefactor );
  396.     if ( freq_base < ( double ) SampleRate / fftlen )
  397.       freq_base = ( double ) SampleRate / fftlen;
  398.     if ( freq_base > max_base )
  399.       freq_base = max_base;
  400.   }
  401.   else
  402.   {
  403.     if ( freq_base < 0 )
  404.       freq_base = 0;
  405.     if ( ( freq_base + SampleRate / ( 2 * freq_scalefactor ) ) > SampleRate / 2 )
  406.       freq_base = SampleRate / 2 - SampleRate / ( 2 * freq_scalefactor );
  407.   }
  408.   if ( logfreq )
  409.     maxfreq = freq_base * exp( log( fftlen / 2 ) / freq_scalefactor );
  410.   else
  411.     maxfreq = freq_base + ( double ) SampleRate / ( freq_scalefactor * 2.0 );
  412. }
  413.  
  414. /*
  415.  *  Set up X axis scales
  416.  */
  417. void
  418. setup_xscale( void )
  419. {
  420.   int        i;
  421.  
  422.   /*
  423.    * Do some range checking on the base and scale factors
  424.    */
  425.   xrange_check(     );
  426.  
  427.   /*
  428.    * Initialize graph x scale (linear or logarithmic). This array points to
  429.    * the bin to be plotted on a given line.
  430.    */
  431.   for ( i = 0; i <= ( WINDOW_RIGHT - WINDOW_LEFT + 1 ); i++ )
  432.   {
  433.     int          val;
  434.     if ( logfreq )
  435.       val = floor( ( double ) fftlen * freq_base / ( double ) SampleRate
  436.          * exp( ( i - 0.45 ) / ( double ) ( WINDOW_RIGHT - WINDOW_LEFT )
  437.             * log( fftlen / 2 ) / freq_scalefactor ) + 0.5 );
  438.     else
  439.       val = floor( ( ( i - 0.45 ) / ( double ) ( WINDOW_RIGHT - WINDOW_LEFT )
  440.              * ( double ) fftlen / 2.0 / freq_scalefactor )
  441.     + ( freq_base / ( double ) SampleRate * ( double ) fftlen ) + 0.5 );
  442.  
  443.     if ( val < 0 )
  444.       val = 0;
  445.     if ( val >= fftlen / 2 )
  446.       val = fftlen / 2 - 1;
  447.  
  448.     if ( i > 0 )
  449.       x2[i - 1] = val;
  450.     if ( i <= ( WINDOW_RIGHT - WINDOW_LEFT ) )
  451.       x[i] = val;
  452.   }
  453.   /* Compute the ending locations for lines holding multiple bins */
  454.   for ( i = 0; i <= ( WINDOW_RIGHT - WINDOW_LEFT ); i++ )
  455.   {
  456.     if ( x2[i] <= ( x[i] + 1 ) )
  457.       x2[i] = 0;
  458.   }
  459.  
  460.  
  461.   /*
  462.    * If lines are repeated on the screen, flag this so that we don't have to
  463.    * recompute the y values.
  464.    */
  465.   for ( i = ( WINDOW_RIGHT - WINDOW_LEFT ); i > 0; i-- )
  466.   {
  467.     if ( x[i] == x[i - 1] )
  468.     {
  469.       x[i] = -1;
  470.       x2[i] = 0;
  471.     }
  472.   }
  473.  
  474.   setup_linscales(  );
  475.   frequency_scale(  );
  476. }
  477.  
  478. /*
  479.  *  Set up linear amplitude scale factors
  480.  */
  481. void
  482. setup_linscales( void )
  483. {
  484.   int        i;
  485.   double    scale;
  486.  
  487.   /*
  488.    * Compute the (linear) y scale factor.
  489.    */
  490.   scale = ( WINDOW_BOTTOM - WINDOW_TOP ) / ( ys * 32768.0 );
  491.  
  492.   shift = 4;            /* Display data has an extra factor of 16 for
  493.                  * better resolution */
  494.  
  495.   {
  496.     /*
  497.      * Make maximum use of available bits (use only 12 bits--other 4 used for
  498.      * higher resolution in the data)
  499.      */
  500.     while ( scale < 4096 )
  501.     {
  502.       scale *= 2;
  503.       shift++;
  504.     }
  505.  
  506.     scale = floor( scale + 0.5 );
  507.  
  508.     for ( i = 0; i < ( WINDOW_RIGHT - WINDOW_LEFT + 1 ); i++ )
  509.     {
  510.       if ( x[i] == -1 )
  511.     yscale[i] = 0;
  512.       else
  513.     yscale[i] = scale;
  514.     }
  515.   }
  516.   shiftscale = 1 / pow( 2, shift );
  517. }
  518.  
  519. void
  520. frequency_scale( void )
  521. {
  522.   int        i;
  523.  
  524.   double    step, freq;
  525.   char        text[20];
  526.   /*
  527.    * Put up the frequency scale.
  528.    */
  529.   draw_bar( WINDOW_LEFT - 10, WINDOW_BOTTOM + 3, WINDOW_RIGHT + 10, 469, 0 );
  530.  
  531.   draw_fontcolor( LABEL_COLOR );
  532.  
  533.   if ( logfreq )
  534.     step = log( fftlen / 2 ) / ( 32.0 * freq_scalefactor );
  535.   else
  536.     step = ( double ) SampleRate / ( 64.0 * freq_scalefactor );
  537.  
  538.   for ( i = 0; i <= 32; i++ )
  539.   {
  540.     int          x = WINDOW_LEFT + ( ( double ) i * ( WINDOW_RIGHT - WINDOW_LEFT ) / 32.0 );
  541.     int          y = WINDOW_BOTTOM + 3;
  542.     draw_line( x, y, x, y + 3, BORDER_COLOR );
  543.     if ( logfreq )
  544.       freq = freq_base * exp( step * i );
  545.     else
  546.       freq = freq_base + i * step;
  547.     if ( freq < 0 )
  548.       freq = 0;
  549.     sprintf( text, "%.0f", freq );
  550.     draw_text_vertical( x - _font_width / 2, y + 6, text );
  551.   }
  552.   draw_fontcolor( TEXT_COLOR );
  553. }
  554.  
  555. void
  556. amplitude_scale( void )
  557. {
  558.   int        i;
  559.   char        text[20];
  560.  
  561.   draw_bar( 0, WINDOW_TOP - 10, WINDOW_LEFT - 3, WINDOW_BOTTOM + 7, 0 );
  562.   draw_bar( WINDOW_RIGHT + 3, WINDOW_TOP - 10, 639, WINDOW_BOTTOM + 7, 0 );
  563.  
  564.   draw_fontcolor( LABEL_COLOR );
  565.  
  566.   /*
  567.    * Put up the amplitude scale
  568.    */
  569.   {
  570.     double      scale = ( double ) ( ys * 32768.0 ) / ( double ) ( WINDOW_BOTTOM - WINDOW_TOP );
  571.     for ( i = 0; i <= 10; i++ )
  572.     {
  573.       int        x = WINDOW_LEFT - 3;
  574.       int        y = WINDOW_BOTTOM - i * ys * 3276.8 / scale;
  575.       draw_line( x, y, x - 3, y, BORDER_COLOR );
  576.       if ( ys > 0.095 )
  577.     sprintf( text, "%4.2f", ( float ) i * ys * 0.1 );
  578.       else
  579.     sprintf( text, "%5.3f", ( float ) i * ys * 0.1 );
  580.       draw_text_right( x - 6, y - _font_height / 2, text );
  581.       draw_line( WINDOW_RIGHT + 3, y, WINDOW_RIGHT + 6, y, BORDER_COLOR );
  582.       draw_text_left( WINDOW_RIGHT + 9, y - _font_height / 2, text );
  583.     }
  584.   }
  585.   draw_fontcolor( TEXT_COLOR );
  586. }
  587.  
  588. void
  589. log_state( void )
  590. {
  591.   draw_bar( 24, 24, 112, 36, 0 );
  592.   draw_fontcolor( LABEL_COLOR );
  593.   if ( log_mode )
  594.     draw_text_left( 24, 24, "Logging ON" );
  595.   else
  596.     draw_text_left( 24, 24, "Logging OFF" );
  597. }
  598.  
  599. void
  600. update_header( void )
  601. {
  602.   char        ach[100];
  603.  
  604.   draw_bar( 0, 0, 639, WINDOW_TOP - 10, 0 );
  605.   draw_bar( WINDOW_LEFT - 5, WINDOW_TOP - 10, WINDOW_RIGHT + 5, WINDOW_TOP - 4, 0 );
  606.  
  607.   draw_fontcolor( TEXT_COLOR );
  608.   sprintf( ach, "Sampling rate: %ld Hz", SampleRate );
  609.   draw_text_centered( SRX, SRY, ach );
  610.   sprintf( ach, "FFT Length: %d points", fftlen );
  611.   draw_text_centered( FLX, FLY, ach );
  612.   sprintf( ach, "Frequency resolution: %.4g Hz", ( double ) SampleRate / ( double ) fftlen );
  613.   draw_text_centered( FRX, FRY, ach );
  614.   if ( dtmf_nr[0] != 0 )
  615.   {
  616.     dtmf_nr[64] = 0;        /* maximum 64 DTMF numbers */
  617.     draw_fontcolor( GRAPH_COLOR );
  618.     draw_text_left( WINDOW_LEFT, MGY - 36, "Number stored in memory: " );
  619.     draw_text_left( WINDOW_LEFT, MGY - 24, dtmf_nr );
  620.     draw_fontcolor( TEXT_COLOR );
  621.   }
  622.   if ( gen_ctcss != CTCSS_MAX )
  623.   {
  624.     draw_fontcolor( GRAPH_COLOR );
  625.     sprintf( ach, "CTCSS %.1f Hz", f_ctcss[gen_ctcss] );
  626.     draw_text_right( WINDOW_RIGHT, 2, ach );
  627.     sprintf( ach, "Error %.2f Hz", err_ctcss );
  628.     draw_text_right( WINDOW_RIGHT, 14, ach );
  629.     draw_fontcolor( TEXT_COLOR );
  630.   }
  631.   if ( dtmf_mode )
  632.   {
  633.     draw_fontcolor( BORDER_COLOR );
  634.     draw_text_left( 24, 0, "DTMF mode" );
  635.     draw_fontcolor( LABEL_COLOR );
  636.     draw_text_left( 24, 60, "DTMF numbers:" );
  637.     draw_threshold_level( TEXT_COLOR );
  638.     log_state(    );
  639.   }
  640.   if ( ctcss_mode )
  641.   {
  642.     draw_fontcolor( BORDER_COLOR );
  643.     draw_text_left( 24, 0, "CTCSS mode" );
  644.     draw_fontcolor( GRAPH_COLOR );
  645.     draw_text_left( 24, 60, "CTCSS Freq:" );
  646.     draw_threshold_level( TEXT_COLOR );
  647.     log_state(    );
  648.   }
  649.   if ( mixers )
  650.   {
  651.     sprintf( ach, "Mic:%3d  Ext:%3d  CD:%3d", mic_level, ext_level, int_level );
  652.     draw_text_left( LVX, LVY, ach );
  653.   }
  654. }
  655.  
  656. void
  657. show_help( void )
  658. {
  659.   draw_bar( 0, 0, 639, WINDOW_TOP - 10, 0 );
  660.   draw_bar( WINDOW_LEFT - 5, WINDOW_TOP - 10, WINDOW_RIGHT + 5, WINDOW_TOP - 4, 0 );
  661.  
  662.   if ( help_mode == 1 )
  663.   {
  664.     draw_text_left( 20, 2, "    'D' Toggle DTMF mode" );
  665.     draw_text_left( 20, 14, "    'T' Toggle CTCSS mode" );
  666.     draw_text_left( 20, 26, "    'I' Input a DTMF number" );
  667.     draw_text_left( 20, 38, "  <TAB> Compose the stored DTMF #" );
  668.     draw_text_left( 20, 50, "    'A' Generate a subAudible tone" );
  669.     draw_text_left( 20, 62, "    'G' Toggle loGfile (dtmf & ctcss)" );
  670.     draw_text_left( 20, 74, "<SPACE> Freeze display" );
  671.  
  672.     draw_text_left( 340, 2, "    'L' Toggle Log/Linear frequency" );
  673.     draw_text_left( 340, 14, "    'R' Change the sampling Rate" );
  674.     draw_text_left( 340, 26, "    'F' Change the FFT length" );
  675.     draw_text_left( 340, 38, "    'P' Toggle Peak display mode" );
  676.     draw_text_left( 340, 50, "    'S' Save State to INI file" );
  677.     draw_text_left( 340, 62, "'H','?' Toggle this Help screen" );
  678.     draw_text_left( 340, 74, "'Q','E' Exit from the program" );
  679.   }
  680.   else
  681.   {
  682.     draw_text_left( 100, 2, "<Left/Right> Shift the frequency axis" );
  683.     draw_text_left( 100, 14, "     '<','>' Expand/contract the frequency axis" );
  684.     draw_text_left( 100, 26, "   <Up/Down> Change the amplitude scale" );
  685.     draw_text_left( 100, 38, " <PgUp/PgDn> Threshold level in DTMF & CTCSS mode" );
  686.     draw_text_left( 100, 50, "<Home>/<End> Move to the minimum/maximum freqency" );
  687.     if ( mixers )
  688.     {
  689.       draw_text_left( 60, 62, "'C' Toggle B&W/color display" );
  690.       draw_text_left( 340, 62, "'V' Refresh display" );
  691.       draw_text_left( 60, 74, "(),[],{} Adjust mic,ext,CD input level" );
  692.     }
  693.     else
  694.     {
  695.       draw_text_left( 60, 62, "'C' Toggle B&W/color display" );
  696.       draw_text_left( 340, 62, "'V' Refresh display" );
  697.     }
  698.   }
  699. }
  700.